#pragma once
#include <common.hpp>
#include "Vector2.hpp"

namespace zzz{
template <typename T>
class MinMax {
public:
#undef max
#undef min
  MinMax():min_(numeric_limits<T>::max()),max_(numeric_limits<T>::is_signed ? -numeric_limits<T>::max() : 0){}
  MinMax(const T &min,const T &max):min_(min),max_(max){}
  MinMax(const T &p):min_(p),max_(p){}
  MinMax(const vector<T> &data):min_(numeric_limits<T>::max()),max_(-numeric_limits<T>::max()){
    *this += data;
  }

  // create from list of vertex
  void Reset() {
    min_=T(numeric_limits<T>::max());
    max_=T(-numeric_limits<T>::max());
  }

  // min and max
  T &Min(){return min_;}
  const T &Min() const{return min_;}
  T &Max(){return max_;}
  const T &Max() const{return max_;}

  // Offset
  void SetOffset(const T &offset)
  {
    min_+=offset;
    max_+=offset;
  }
  // Center
  T Center() const{return (min_+max_)*0.5;}

  // Difference
  T Diff() const{return max_-min_;}

  Vector<2, T> Range() const {return Vector<2, T>(min_, max_);}

  bool IsLegal() const {
    if (min_>max_)
      return false;
    return true;
  }

  bool IsEmpty() const {
    return min_==max_;
  }

  void AddData(const T &p) {
    if (min_>p) min_=p;
    if (max_<p) max_=p;
  }

  template<typename T1>
  void AddData(const T1& _begin, const T1& _end) {
    for (T1 i = _begin; i != _end; i++)
      AddData(*i);
  }

  /// Boolean union
  void operator+=(const T &p) {
    AddData(p);
  }
  
  /// Boolean union
  void operator+=(const std::vector<T> &p) {
    AddData(p.begin(), p.end());
  }
  
  /// Boolean union
  void operator+=(const MinMax<T> &box) {
    AddData(box.min_);
    AddData(box.max_);
  }

  const MinMax<T>& operator+(const MinMax<T> &box) const {
    MinMax<T> ret(*this);
    ret.AddData(box);
    return ret;
  }

  /// Boolean intersection
  void operator*=(const MinMax<T> &box) {
    if (min_<box.min_) min_=box.min_;
    if (max_>box.max_) max_=box.max_;
  }

  const MinMax<T>& operator*(const MinMax<T> &box) const {
    MinMax<T> ret(*this);
    ret*=box;
    return ret;
  }

  /// Box equality operator
  bool operator==(const MinMax<T> &box) const {
    return min_==box.min_ && max_==box.max_;
  }

  /// Volumetric classification
  bool IsInside(const T &pos) const {
    if (!Within<T>(min_,pos,max_)) 
      return false;
    return true;
  }

  /// Intersection between boxes
  bool IsIntersect(const MinMax<T> &box) const {
    if (min_ > box.max_) return false;
    if (max_ < box.min_) return false;
    return true;
  }

  static MinMax<T> ZERO() {
    return MinMax(T(0), T(0));
  }

  static MinMax<T> INFINITY() {
    return MinMax();
  }

  T min_, max_;
};

typedef MinMax<int> MinMaxi;
typedef MinMax<float> MinMaxf;
typedef MinMax<double> MinMaxd;

SIMPLE_IOOBJECT(MinMaxi);
SIMPLE_IOOBJECT(MinMaxf);
SIMPLE_IOOBJECT(MinMaxd);
}
